package vg.modules.conveyor;

import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;

import ru.nsu.fit.iconveyor.conveyor.Conveyor;
import ru.nsu.fit.iconveyor.conveyor.Globals;
import ru.nsu.fit.iconveyor.conveyor.node.Node;

import vg.services.data_base_manager.data.graph.Attribute;
import vg.services.data_base_manager.data.graph.Edge;
import vg.services.data_base_manager.data.graph.Graph;
import vg.services.data_base_manager.data.graph.Vertex;

public class Converter {
	public static Conveyor visualGraph2conveyor(Graph graph, Map<String, Class<Node>> classes) throws Exception {
		Map<Vertex, Collection<Edge>> map_vertex_src_edge = new HashMap<Vertex, Collection<Edge>>();
		Map<Vertex, Collection<Edge>> map_vertex_trg_edge = new HashMap<Vertex, Collection<Edge>>();
		Collection<Vertex> vertices = graph.getVertices();
		Collection<Edge> edges = graph.getEdges();
		
		if (vertices != null && edges != null) {
			for (Vertex v : vertices) {
				Collection<Edge> list_src_edges = new ArrayList<Edge>();
				Collection<Edge> list_trg_edges = new ArrayList<Edge>();
				map_vertex_src_edge.put(v, list_src_edges);
				map_vertex_trg_edge.put(v, list_trg_edges);
				for (Edge e : edges) {
					if (e.getSource().hashCode() == v.hashCode() && e.getSource().equals(v)) {
						list_src_edges.add(e);
					}
					if (e.getTarget().hashCode() == v.hashCode() && e.getTarget().equals(v)) {
						list_trg_edges.add(e);
					}
				}
			}
		}
		
		Conveyor converter = new Conveyor();

		if (vertices != null) {
			for (Vertex v : vertices) {
				Attribute executorAttr = v.getAttribute(Globals.EXECUTOR_ATTR_NAME);
				if (executorAttr != null) {
					Class<Node> clazz = classes.get(executorAttr.getValue());
					if (clazz != null) {
						Collection<Edge> src = map_vertex_src_edge.get(v);
						Collection<Edge> trg = map_vertex_trg_edge.get(v);
						
						Node node = clazz.getDeclaredConstructor(String.class).newInstance(generateId4Node(v));
						for (Edge e : src) {
							Attribute srcAttr = e.getAttribute(Globals.OUTPUT_ATTR_NAME);
							String outputAttrValue = srcAttr.getValue();
							node.getOutputNodeConnectionByName(outputAttrValue).setChannelId(generateId4Channel(e));
						}
						for (Edge e : trg) {
							Attribute trgAttr = e.getAttribute(Globals.INPUT_ATTR_NAME);
							String inputAttrValue = trgAttr.getValue();
							node.getInputNodeConnectionByName(inputAttrValue).setChannelId(generateId4Channel(e));
						}
                        converter.addNode(node);

                        // add attributes
                        for (Attribute a : v.getAttributes()) {
                            node.setParameter(a.getName(), a.getValue());
                        }
					} else {
						throw new Exception("Bad value of '" + Globals.EXECUTOR_ATTR_NAME + "' attribute = " + executorAttr.getValue());
					}
				} else {
					throw new Exception("One or more vertex hasn't '" + Globals.EXECUTOR_ATTR_NAME + "' attribute");
				}
			}
		}
		
		if (edges != null) {
			for (Edge e : edges) {
				Attribute inputNumberAttr = e.getAttribute(Globals.INPUT_ATTR_NAME);
				Attribute outputNumberAttr = e.getAttribute(Globals.OUTPUT_ATTR_NAME);
				if (inputNumberAttr != null && outputNumberAttr != null) {
                    converter.addChannelId(generateId4Channel(e));
				} else {
					throw new Exception("One or more channels hasn't '" + Globals.INPUT_ATTR_NAME + "' or '" + Globals.OUTPUT_ATTR_NAME + "' attributes");
				}
			}
		}

		return converter;
	}

	public static Graph conveyor2visualGraph(Conveyor conveyor) throws Exception {
		
		return null;
	}
	
//==============================================================================
//=================PRIVATE METHODS----------------------------------------------
	private static String generateId4Node(Vertex vertex) {
		return "v_" + vertex.getStorableId();
	}
	
	private static String generateId4Channel(Edge edge) {
		return "e_" + edge.getStorableId();
	}	
}
